/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/package org.activequant.util.charting;

import java.util.ArrayList;
import java.util.List;

import org.activequant.core.domainmodel.InstrumentSpecification;
import org.activequant.core.domainmodel.account.Order;
import org.activequant.core.domainmodel.account.OrderBook;
import org.activequant.core.domainmodel.account.OrderHistory;
import org.activequant.core.domainmodel.data.Candle;
import org.activequant.core.domainmodel.data.CandleSeries;
import org.activequant.core.domainmodel.events.OrderEvent;
import org.activequant.core.domainmodel.events.OrderExecutionEvent;
import org.activequant.core.types.OrderSide;
import org.activequant.core.types.TimeStamp;
import org.activequant.core.types.Tuple;
import org.activequant.core.util.TimeSeriesUtils;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.DefaultOHLCDataset;
import org.jfree.data.xy.OHLCDataItem;


/**
 * 
 * creates a candle stick chart. <br/>
 * CandlestickChart extends Chart.<br/>
 * Holds the following inherited variables:
 * <ul>
 * <li>chart(JFreeChart)</li>
 * <li>dataset(TimeSeriesCollection)</li>
 * <li>drawColor(Color)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [01.06.2007] Created (Ulrich Staudinger)<br>
 *  - [29.09.2007] Removed warnings (Erik Nijkamp)<br>
 *  - [18.10.2007] Added facility to add a textual annotation (Ulrich Staudinger)<br>
 *
 *  @author Ulrich Staudinger
 */
public class CandlestickChart extends Chart {

	/**
	 * calling super constructor. <br/>
	 * Constructs a CandlestickChart(extends Chart) whose inherited chart(JFreeChart) is a time series chart.<br/>
	 * A time series chart is an {@link XYPlot} with a {@link DateAxis} for the x-axis and a  {@link NumberAxis} for the y-axis.  The default renderer is an {@link XYLineAndShapeRenderer}. <P>
     * A convenient dataset to use with this chart is a  {@link org.jfree.data.time.TimeSeriesCollection}.<br/>
     * The inherited chart(JFreeChart) has no title(String), empty timeAxisLabel(String) and valueAxisLabel(String), has no dataset set, a legend is required but no tooltips and URLs.
	 */
	public CandlestickChart(){
		super();
	}
	/**
	 * Constructs a CandlestickChart(extends Chart) using the given ts(CandleSeries) to initialize its inherited chart(JFreeChart):<br/>
	 * Adds a Candle Series Chart with a title="underlying" to the XYPlot of the inherited chart(JFreeChart) using the given ts(CandleSeries) as its data items:<br/>
	 * -Creates a setOHLC(DefaultOHLCDataset) with a title="underlying", holding an OHLCDataItem for each Candle in the given ts(CandleSeries).<br/>
	 * -Creates a c1(CandlestickRenderer) whose <code>AutoWidthFactor=0</code> and <code>AutoWidthGap=0.3</code><br/>
	 * -Gets plot1(XYPlot) as the XYPlot of the inherited chart(JFreeChart)<br/>
	 * -Sets the dataset at the 0 index of the plot1(XYPlot) with the setOHLC(DefaultOHLCDataset) and sets its
	 * renderer with the c1(CandlestickRenderer)
	 * @param ts
	 */
	public CandlestickChart(CandleSeries ts){
		super();
		setCandleSeries(ts);
	}
	
	/**
	 * use this to specify the timeseries information for this chart. <br/>
	 * Adds a Candle Series Chart with a title="underlying" to the XYPlot of the inherited chart(JFreeChart) using the given ts(CandleSeries) as its data items:<br/>
	 * -Creates a setOHLC(DefaultOHLCDataset) with a title="underlying", holding an OHLCDataItem for each Candle in the given ts(CandleSeries).<br/>
	 * -Creates a c1(CandlestickRenderer) whose <code>AutoWidthFactor=0</code> and <code>AutoWidthGap=0.3</code><br/>
	 * -Gets plot1(XYPlot) as the XYPlot of the inherited chart(JFreeChart)<br/>
	 * -Sets the dataset at the 0 index of the plot1(XYPlot) with the setOHLC(DefaultOHLCDataset) and sets its
	 * renderer with the c1(CandlestickRenderer)
	 * created on 07.05.2006
	 * @param ts
	 */
	public void setCandleSeries(CandleSeries ts) {
		setCandleSeries("underlying", ts);
	}
	
	/**
	 * use this to specify the timeseries information for this chart. <br/>
	 * Adds a Candle Series Chart with the given title(String) to the XYPlot of the inherited chart(JFreeChart) using the given ts(CandleSeries) as its data items:<br/>
	 * -Creates a setOHLC(DefaultOHLCDataset) with the given title(String), holding an OHLCDataItem for each Candle in the given ts(CandleSeries).<br/>
	 * -Creates a c1(CandlestickRenderer) whose <code>AutoWidthFactor=0</code> and <code>AutoWidthGap=0.3</code><br/>
	 * -Gets plot1(XYPlot) as the XYPlot of the inherited chart(JFreeChart)<br/>
	 * -Sets the dataset at the 0 index of the plot1(XYPlot) with the setOHLC(DefaultOHLCDataset) and sets its
	 * renderer with the c1(CandlestickRenderer)<br/>
	 * created on 07.05.2006
	 * @param title
	 * @param ts
	 */
	public void setCandleSeries(String title, CandleSeries ts) {
		
		OHLCDataItem[] ohlcs = new OHLCDataItem[ts.size()];
		for (int i = 0; i < ohlcs.length; i++) {
			Candle c = ts.get(ohlcs.length - i - 1);
			if(c!=null){
				OHLCDataItem item = new OHLCDataItem(c.getTimeStamp().getDate(), c.getOpenPrice(), c.getHighPrice(), c.getLowPrice(),c.getClosePrice(), c.getVolume());
				ohlcs[i] = item;
			}
			else{
				log.warn("[setCandleSeries] Candle was null.");
			}
		}
		
		DefaultOHLCDataset setOHLC = new DefaultOHLCDataset(title, ohlcs);
		CandlestickRenderer c1=new CandlestickRenderer();
        

		c1.setAutoWidthFactor(0.0);
		c1.setAutoWidthGap(0.3);
		
		XYPlot plot1=chart.getXYPlot();
		
		plot1.setDataset(0, setOHLC);
		plot1.setRenderer(0, c1);
		
	}
	/**
	 * Returns an OrderHistory[] array holding the OrderHistory of each Order in the given book(OrderBook) whose instrumentSpecification(InstrumentSpecification)
	 * matches the given spec(InstrumentSpecification)
	 * @param book
	 * @param spec
	 * @return
	 */
	private OrderHistory[] getOrdersByInstrumentSpecification(OrderBook book, InstrumentSpecification spec) {
		List<OrderHistory> list = new ArrayList<OrderHistory>();
		
		for(OrderHistory h : book.getHistories()) {
			if(h.getOrder().getInstrumentSpecification().equals(spec)) {
				list.add(h);
			}
			
		}
		
		return list.toArray(new OrderHistory[list.size()]);
	}
	
	
	/**
	 * helper method to draw the executions into this chart.<br/>
	 * Finds relevant executions from the given orderBook(OrderBook) for the given referenceSeries(CandleSeries) and adds them as 
	 * <strong>Up</strong> or <strong>Down</strong> Arrow annotations on the XYPlot of the inherited chart(JFreeChart)<br/>
	 * It also draws a "Positions" line calculated from the given orderBook(OrderBook):<br/>
	 * <strong>1.</strong> Gets the orderHistories(OrderHistory[]) holding the OrderHistory of each Order in the given orderBook(OrderBook) 
	 * whose instrumentSpecification(InstrumentSpecification) matches the instrumentSpecification(InstrumentSpecification) of the seriesSpecification(SeriesSpecification)
	 * of the given referenceSeries(CandleSeries)<br/>
	 * <strong>2.</strong> Iterates those orderHistories(OrderHistory[]) and looks at the events(List&lt;OrderEvent&gt;) of each OrderHistory.<br/>
	 * If it finds an exe(OrderExecutionEvent):<br/>
	 * -looks at its eventTimeStamp(TimeStamp) in order to determine the overlapping c(Candle) in the given referenceSeries(CandleSeries).<br/>
	 * -Then, it adds/draws an <strong>Up</strong> or <strong>Down</strong> Arrow annotation on the XYPlot of the inherited chart(JFreeChart) using the timeStamp of the c(Candle) and 
	 * price(double) of the exe(OrderExecutionEvent) as its x and y coordinates. The Arrow is <strong>Up</strong> if the OrderSide of the Order is BUY, and <strong>Down</strong> for 
	 * a SELL or SHORT_SELL.<br/>
	 * <strong>3.</strong> Then it iterates the given referenceSeries(CandleSeries) (backwards - from oldest to latest) and for each Candle it tries to find an Order (among the orderHistories(OrderHistory[])) whose
	 * orderTimeStamp(TimeStamp) matches the one of the Candle. Looks at the quantity(double) of the Order, and its OrderSide to come up with the data needed to draw a "Positions" line.
	 * 
	 * @param referenceSeries
	 * @param orderBook
	 * @param execBook
	 */
	public void drawExecutions(CandleSeries referenceSeries, OrderBook orderBook) {
		OrderHistory[] orderHistory = getOrdersByInstrumentSpecification(orderBook, referenceSeries.getInstrumentSpecification());
		
		for(OrderHistory oh : orderHistory) {			
			for(OrderEvent e : oh.getEvents()) {
				if(e instanceof OrderExecutionEvent) {
					OrderExecutionEvent exe = (OrderExecutionEvent) e;
					Order o = oh.getOrder();
					// fetch the position time,
					int positionInSeries = TimeSeriesUtils.getFeasibleTimeStampPosition(Candle.class, referenceSeries, exe.getEventTimeStamp());					
					// make sure a candle is found. 
					if(positionInSeries>0){
						Candle c = referenceSeries.get(positionInSeries-1);
						// draw the execution. 
						if(o.getOrderSide().equals(OrderSide.BUY)){
							// draw up arrow above price 
							chart.getXYPlot().addAnnotation(getUpArrow(c.getTimeStamp().getDate().getTime(), exe.getPrice()));
						}
						else if(o.getOrderSide().equals(OrderSide.SELL)){
							// draw down arrow above price 
							chart.getXYPlot().addAnnotation(getDownArrow(c.getTimeStamp().getDate().getTime(), exe.getPrice()));
						}
						if(o.getOrderSide().equals(OrderSide.SHORT_SELL)){
							// draw down arrow below price 
							chart.getXYPlot().addAnnotation(getDownArrow(c.getTimeStamp().getDate().getTime(), exe.getPrice()));
						}
					}
				}
			}
		}
		
		// iterate over the candles and build the position count.
		List<Tuple<TimeStamp,Double>> posLine = new ArrayList<Tuple<TimeStamp, Double>>();
		double positionCount = 0.0;
		for(int i=referenceSeries.size()-2;i>0;i--){
			Candle c = referenceSeries.get(i);
			// try to see if we have an order for that date ....
			for(OrderHistory oh : orderHistory) {
				Order o = oh.getOrder();
				if(o.getOrderTimeStamp().equals(c.getTimeStamp())){
					positionCount += (o.getOrderSide()==OrderSide.BUY)?o.getQuantity():-o.getQuantity();
				}
			}
			
			if(positionCount!=0.0){
				double change  = 0.001;
			
				double placement = c.getClosePrice() + (Math.signum(positionCount)*change);
				// 	calculate the value where to draw it. 
				Tuple<TimeStamp,Double> t = new Tuple<TimeStamp, Double>(c.getTimeStamp(),placement);
				posLine.add(t);
			}
			
		}
		addDotSeriesChart("Positions", posLine);
	}
	
}
